﻿using System;
using System.Collections.Generic;
using System.IO;
namespace ImryStefanGAnamespace
{
    /// <summary>
    /// Describes a solution to a CVRP 
    /// </summary>
    public class CVRPSolution : IComparable
    {
        public List<Segment> routesInSolution;

        internal void WriteToFile(string p)
        {
            StreamWriter file = new StreamWriter(p);
            for (int i = 1; i < routesInSolution.Count; i++)
            {
                file.Write("Route #" + i + ":");
                for (int j = 1; j < routesInSolution[i].nodesOnSegment.Count - 1; i++)
                {
                    file.Write(" " + routesInSolution[i].nodesOnSegment[j]);
                }
                file.WriteLine();
            }
            file.WriteLine("Cost " + TotalCost());
            file.Close();
        }

        internal void DisplayRoutes()
        {
            for (int i = 0; i < routesInSolution.Count; i++)
            {
                Console.Write("Route #" + i + ":");
                for (int j = 1; j < routesInSolution[i].nodesOnSegment.Count - 1; j++)
                {
                    Console.Write(" " + routesInSolution[i].nodesOnSegment[j]);
                }
                Console.WriteLine();
            }
        }

        internal void FeasibilityCheck()
        {

            int[] nodes = new int[Program.vrpData.Dimension];
            nodes[0] = 1;

            for (int i = 0; i < routesInSolution.Count; i++)
            {
                double demand = 0;
                for (int j = 1; j <= routesInSolution[i].numberOfNodesVisited; j++)
                {
                    demand = Program.vrpData.Demands[routesInSolution[i].nodesOnSegment[j]];
                    nodes[routesInSolution[i].nodesOnSegment[j]]++;
                }
                if (demand > Program.vrpData.Capacity)
                    throw new Exception("A route in the solution exceeds capacity!");
            }

            for (int i = 1; i < Program.vrpData.Dimension; i++)
            {
                if (nodes[i] > 1)
                    throw new Exception("Using node " + i + " too many times!");
                if (nodes[i] < 1)
                    throw new Exception("Not visiting node " + i + " !");
            }
            Console.WriteLine("Feasible. Cost = " + TotalCost());
        }

        internal void RandomlyMutate()
        {
            int i = Program.rand.Next(Program.vrpData.Dimension - 1) + 1;
            int j = Program.rand.Next(Program.vrpData.Dimension - 2) + 1;
            if (i <= j) j++;

            int iRoute = -1;
            int iNode = -1;
            int jRoute = -1;
            int jNode = -1;

            for (int routeIndex = 0; routeIndex < routesInSolution.Count; routeIndex++)
            {
                for (int nodeIndex = 0; nodeIndex < routesInSolution[routeIndex].nodesOnSegment.Count; nodeIndex++)
                {
                    if (routesInSolution[routeIndex].nodesOnSegment[nodeIndex] == i)
                    {
                        iRoute = routeIndex;
                        iNode = nodeIndex;
                    }
                    if (routesInSolution[routeIndex].nodesOnSegment[nodeIndex] == j)
                    {
                        jRoute = routeIndex;
                        jNode = nodeIndex;
                    }
                }

            }

            routesInSolution[iRoute].Replace(iNode, j);
            routesInSolution[jRoute].Replace(jNode, i);
        }

        public CVRPSolution()
        {
            routesInSolution = new List<Segment>();
        }

        public CVRPSolution Clone()
        {
            CVRPSolution theClone = new CVRPSolution();
            for (int i = 0; i < routesInSolution.Count; i++)
                theClone.routesInSolution.Add(routesInSolution[i].Clone());
            return theClone;
        }

        public int CompareTo(object obj)
        {
            CVRPSolution otherSolution = obj as CVRPSolution;
            double otherOverallFitness = otherSolution.TotalCost();
            return otherOverallFitness.CompareTo(TotalCost());
        }

        internal double TotalCost()
        {
            double tc = 0;
            for (int routeIndex = 0; routeIndex < routesInSolution.Count; routeIndex++)
                tc += routesInSolution[routeIndex].CalculateTotalCost();
            return tc;
        }

    }
}